using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace PeDALS.Tools.AZ.PSTArchive.PSTData
{
    public class PSTBTreePage : TreeEntry
    {
        private List<TreeEntry> mteSubEntries = new List<TreeEntry>();
        private List<TreeEntry> mteBlankEntries = new List<TreeEntry>();
        private byte mbEntryCount;
        private byte mbMaxEntries;
        private byte mbEntryLength;
        private byte mbTreeLevel;
        private UInt64 m64TreeBIDrawTreeKey;
        private UInt64 m64TreeBIDrawRequest;
        private long mlngTreeAddress;

        public PSTBTreePage(BinaryReader brReader, UInt64 ui64BIDrawTreeKey, UInt64 ui64BIDrawRequest, long lngTreeAddress, PageTypes ptTypeRequest, byte bTreeLevelRequest, bool blnUnicode, string strPath, long lngEntryAddress) : base(strPath, lngEntryAddress)
        {
            m64TreeBIDrawTreeKey = ui64BIDrawTreeKey;
            m64TreeBIDrawRequest = ui64BIDrawRequest;
            mlngTreeAddress = lngTreeAddress;
            UInt32 ui32Padding;
            long lngEntriesLength = 488 + (blnUnicode ? 0 : 4);
            brReader.BaseStream.Seek(Convert.ToInt64(mlngTreeAddress + lngEntriesLength), SeekOrigin.Begin);
            if (!blnUnicode) ui32Padding = brReader.ReadUInt32();
            mbEntryCount = brReader.ReadByte();
            mbMaxEntries = brReader.ReadByte();
            mbEntryLength = brReader.ReadByte();
            mbTreeLevel = brReader.ReadByte();
            if (blnUnicode) ui32Padding = brReader.ReadUInt32();
            PSTPageTrailer ptTrailer = new PSTPageTrailer(brReader, blnUnicode);
            brReader.BaseStream.Seek(Convert.ToInt64(mlngTreeAddress), SeekOrigin.Begin);
            if ((ptTrailer.BIDraw == ui64BIDrawRequest) && (ptTrailer.ptType == ptTrailer.ptTypeRepeat) && (ptTrailer.ptType == ptTypeRequest))  
            {
                int intIndex = 0;
                long lngSubEntryAddress;
                string strSubPath;
                do
                {
                    lngSubEntryAddress = brReader.BaseStream.Position;
                    strSubPath = string.Format("{0}\\{1}", this.EntryPath, intIndex.ToString());
                    if (mbTreeLevel > 0)
                    {
                        UInt64 ui64BIDrawSubTreeKey = blnUnicode ? brReader.ReadUInt64() : Convert.ToUInt64(brReader.ReadUInt32());
                        UInt64 ui64BIDrawSubTree = blnUnicode ? brReader.ReadUInt64() : Convert.ToUInt64(brReader.ReadUInt32());
                        long lngSubTreeAddress = blnUnicode ? brReader.ReadInt64() : Convert.ToInt64(brReader.ReadInt32());
                        if ((ui64BIDrawSubTreeKey > 0) && (ui64BIDrawSubTree > 0) && (lngSubTreeAddress > 0))
                        {
                            if (lngSubTreeAddress > 0 && lngSubTreeAddress < brReader.BaseStream.Length)
                            {
                                long lngCurrentAddress = brReader.BaseStream.Position;
                                mteSubEntries.Add(new PSTBTreePage(brReader, ui64BIDrawSubTreeKey, ui64BIDrawSubTree, lngSubTreeAddress, ptTrailer.ptType, Convert.ToByte(mbTreeLevel - 1), blnUnicode, strSubPath, lngSubEntryAddress));
                                brReader.BaseStream.Seek(lngCurrentAddress, SeekOrigin.Begin);
                            }
                        }
                        else
                        {
                            mteBlankEntries.Add(((ui64BIDrawSubTreeKey > 0) || (ui64BIDrawSubTree > 0) || (lngSubTreeAddress > 0)) ? new TreeEntry(strSubPath, lngSubEntryAddress, false, string.Format("Intermediate BTreePage entry error:  Path = {0} at 0x{1:x8}; ui64BIDrawSubTreeKey = 0x{2:x8}; ui64BIDrawSubTree = 0x{3:x8}; lngSubTreeAddress = 0x{4:x8}", strSubPath, lngSubEntryAddress, ui64BIDrawSubTreeKey, ui64BIDrawSubTree, lngSubTreeAddress)) : new TreeEntry(strSubPath, lngSubEntryAddress));
                        }
                    }
                    else
                    {
                        if (ptTrailer.ptType == PageTypes.NodeBTree)
                        {
                            UInt64 ui64NIDraw = blnUnicode ? brReader.ReadUInt64() : Convert.ToUInt64(brReader.ReadUInt32());
                            UInt64 ui64BIDrawData = blnUnicode ? brReader.ReadUInt64() : Convert.ToUInt64(brReader.ReadUInt32());
                            UInt64 ui64BIDrawSub = blnUnicode ? brReader.ReadUInt64() : Convert.ToUInt64(brReader.ReadUInt32());
                            UInt64 ui64NIDrawParent = Convert.ToUInt64(brReader.ReadUInt32());
                            if (blnUnicode) ui32Padding = brReader.ReadUInt32();
                            if ((ui64NIDraw > 0) && (ui64BIDrawData > 0))
                            {
                                mteSubEntries.Add(new TreeNodeEntry(ui64NIDraw, ui64BIDrawData, ui64BIDrawSub, ui64NIDrawParent, strSubPath, lngSubEntryAddress));
                            }
                            else
                            {
                                mteBlankEntries.Add(((ui64NIDraw > 0) || (ui64BIDrawData > 0) || (ui64BIDrawSub > 0)) ? new TreeEntry(strSubPath, lngSubEntryAddress, false, string.Format("Node entry error:  Path = {0} at 0x{1:x8}; ui64NIDraw = 0x{2:x8}; ui64BIDrawData = 0x{3:x8}; ui64BIDrawSub = 0x{4:x8}", strSubPath, lngSubEntryAddress, ui64NIDraw, ui64BIDrawData, ui64BIDrawSub)) : new TreeEntry(strSubPath, lngSubEntryAddress));
                            }
                        }
                        else if (ptTrailer.ptType == PageTypes.BlockBTree)
                        {
                            UInt64 ui64BIDraw = blnUnicode ? brReader.ReadUInt64() : Convert.ToUInt64(brReader.ReadUInt32());
                            long lngBlockAddress = blnUnicode ? brReader.ReadInt64() : Convert.ToInt64(brReader.ReadInt32());
                            short shtBlockLength = brReader.ReadInt16();
                            short shtBlockReferenceCount = brReader.ReadInt16();
                            if (blnUnicode) ui32Padding = brReader.ReadUInt32();
                            if ((ui64BIDraw > 0) && (lngBlockAddress > 0) && (shtBlockLength > 0) && (shtBlockReferenceCount > 0))
                            {
                                mteSubEntries.Add(new TreeBlockEntry(ui64BIDraw, lngBlockAddress, shtBlockLength, shtBlockReferenceCount, strSubPath, lngSubEntryAddress));
                            }
                            else
                            {
                                mteBlankEntries.Add(((ui64BIDraw > 0) || (lngBlockAddress > 0) || (shtBlockLength != 0) || (shtBlockReferenceCount != 0)) ? new TreeEntry(strSubPath, lngSubEntryAddress, false, string.Format("Block entry error:  Path = {0} at 0x{1:x8}; ui64BIDraw = 0x{2:x8}; lngBlockAddress = 0x{3:x8}; shtBlockLength = {4}; shtBlockReferenceCount = {5}", strSubPath, lngSubEntryAddress, ui64BIDraw, lngBlockAddress, shtBlockLength, shtBlockReferenceCount)) : new TreeEntry(strSubPath, lngSubEntryAddress));
                            }
                        }
                    }
                    intIndex++;
                } while (intIndex < mbEntryCount);
                //} while (intIndex < mbMaxEntries);
            }
            else
            {
                System.Diagnostics.Trace.Write(string.Format("PSTBTreePage Error on Path:  {0}(rB=0x{1:X}; tB=0x{2:X}; rT=0x{3:X}; tT=0x{4:X}; a=0x{5:X} )", this.EntryPath, ui64BIDrawRequest, ptTrailer.BIDraw, ptTypeRequest, ptTrailer.ptType, lngTreeAddress));
            }
            lngEntriesLength++;
        }

        public byte EntryCount
        {
            get { return mbEntryCount; }
        }

        public byte MaxEntries
        {
            get { return mbMaxEntries; }
        }

        public List<TreeEntry> SubEntries
        {
            get
            {
                return mteSubEntries;
            }
        }

        public List<TreeEntry> BlankEntries
        {
            get
            {
                return mteBlankEntries;
            }
        }
    }
}
